`timescale 1ns/1ns
`default_nettype none

module data_pattern (
    // system signal
    input  wire         I_sclk,  // 125M
    input  wire         I_rst_n,
    input  wire [8:0]   I_cfg_win_col_num,   // 带载列数（宽度）
    input  wire [8:0]   I_cfg_win_row_num,   // 带载行数（高度）
    // input  frame
    input  wire         I_frame_start,
    
    input  wire [15:0]  I_pixel_data,
    
    input  wire [3:0]   I_mode,
    
    input  wire [7:0]   I_x,
    input  wire [7:0]   I_y,
    // output frame
    output reg  [5:0]   O_burst_row,
    output reg  [6:0]   O_burst_col,
    output reg          O_pixel_en,
    output reg  [15:0]  O_pixel_data
);
//------------------------Parameter----------------------
// mode
localparam [3:0]
    BLACK  = 0,
    WHITE  = 1,
    GRAY   = 2,
    RED    = 3,
    GREEN  = 4,
    BLUE   = 5,
    STRIP0 = 6,
    STRIP1 = 7,
    STRIP2 = 8,
    STRIP3 = 9;

// fsm
localparam [3:0]
    IDLE  = 0,
    START = 1,
    WAIT0 = 2,
    DAT_R = 3,
    DAT_G = 4,
    DAT_B = 5,
    LOOP  = 6,
    OVER  = 7,
    WAIT1 = 8;

// frame detect
localparam
  //LOST_TIME = 'd1000; // 1000ms
    LOST_TIME = 'd60;   // 1000ms

// output timing
localparam
    HBLANK = 10,
    VBLANK = 10;
    
// timer
localparam
  //MOVE_TIME = 'd1000; // 1000ms
    MOVE_TIME = 'd60;   // 1000ms

// key timer
localparam
  //KEY_TIME = 'd100; // 100ms
    KEY_TIME = 'd6;   // 100ms
    

//------------------------Local signal-------------------
// fsm
reg  [3:0]  state;
reg  [3:0]  next;
reg  [9:0]  x;
reg  [9:0]  y;
reg  [11:0] cnt;

// frame detect
reg         power_on;
reg         enable;
reg         frame_lost;
reg  [9:0]  lost_cnt;

// mode
reg  [3:0]  mode;
reg  [2:0]  key_sr;
reg  [6:0]  key_cnt;
reg         key_press;

// output frame
reg  [9:0]  move_cnt;
reg         move_flag;
reg  [2:0]  step;
wire [2:0]  tmp0;
wire [2:0]  tmp1;


reg [9:0]step_x;
reg [9:0]step_y;
//------------------------Instantiation------------------

//------------------------Body---------------------------
//{{{+++++++++++++++++++++fsm++++++++++++++++++++++++++++
// state
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        state <= IDLE;
    else
        state <= next;
end

// next
always @(*) begin
    case (state)
        IDLE: begin
            if(I_frame_start)
                next = START;
            else
                next = IDLE;
        end

        START: begin
            next = WAIT0;
        end

        WAIT0: begin
            if (cnt == HBLANK)
                next = DAT_R;
            else
                next = WAIT0;
        end

        DAT_R: begin
            if (x == I_cfg_win_col_num - 1'b1)
                next = LOOP;
            else
                next = DAT_R;
        end

        LOOP: begin
            if (y == I_cfg_win_row_num - 1'b1)
                next = OVER;
            else
                next = WAIT0;
        end

        OVER: begin
            next = WAIT1;
        end

        WAIT1: begin
            if (cnt == VBLANK)
              //next = START;
                next = IDLE;
            else
                next = WAIT1;
        end

        default: begin
            next = IDLE;
        end
    endcase
end

// x
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        x <= 1'b0;
    else if (state == WAIT0)
        x <= 1'b0;
    else if (state == DAT_R)
        x <= x + 1'b1;
end

// y
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        y <= 1'b0;
    else if (state == START)
        y <= 1'b0;
    else if (state == LOOP)
        y <= y + 1'b1;
end

// cnt
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        cnt <= 1'b1;
    else if (state == START || state == LOOP)
        cnt <= 1'b1;
    else
        cnt <= cnt + 1'b1;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++



//{{{+++++++++++++++++++++mode+++++++++++++++++++++++++++
// mode
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        mode <= WHITE;
    else 
        mode <= I_mode;
end

// O_pixel_en
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_pixel_en <= 1'b0;
    else if (state == DAT_R)
        O_pixel_en <= 1'b1;
    else
        O_pixel_en <= 1'b0;
end

// O_pixel_data
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_pixel_data <= 1'b0;
    else begin
        case (mode)
            BLACK: begin
                O_pixel_data <= 16'h00;
            end

            WHITE: begin
                O_pixel_data <= I_pixel_data;
            end

            GRAY: begin
                // O_pixel_data <= x[9:0];
                if (I_x == x && I_y == y)
                    O_pixel_data <= I_pixel_data;
                else
                    O_pixel_data <= 16'h00;
            end

            RED: begin
                // if (state == DAT_R)
                if (step_x == x && step_y == y)
                    O_pixel_data <= I_pixel_data;
                else
                    O_pixel_data <= 16'h00;
            end

            GREEN: begin
                if (I_x == x)
                    O_pixel_data <= I_pixel_data;
                else
                    O_pixel_data <= 16'h00;
            end

            BLUE: begin
                if (I_y == y)
                    O_pixel_data <= I_pixel_data;
                else
                    O_pixel_data <= 16'h00;
            end

            STRIP0: begin
                if (y[2:0] == step)
                    O_pixel_data <= I_pixel_data;
                else
                    O_pixel_data <= 16'h00;
            end

            STRIP1: begin
                if (x[2:0] == step)
                    O_pixel_data <= I_pixel_data;
                else
                    O_pixel_data <= 16'h00;
            end

            STRIP2: begin
                if (tmp0 == step)
                    O_pixel_data <= I_pixel_data;
                else
                    O_pixel_data <= 16'h00;
            end

            STRIP3: begin
                if (tmp1 == step)
                    O_pixel_data <= I_pixel_data;
                else
                    O_pixel_data <= 16'h00;
            end
        endcase
    end
end

// O_burst_row
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_burst_row <= 1'b0;
    else
        O_burst_row <= y;
end

// O_burst_col
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_burst_col <= 1'b0;
    else
        O_burst_col <= x;
end

// move_cnt
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        move_cnt <= MOVE_TIME;
    else if (move_flag)
        move_cnt <= MOVE_TIME;
    else if (I_frame_start)
        move_cnt <= move_cnt - 1'b1;
end

// move_flag
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        move_flag <= 1'b0;
    else if (I_frame_start && move_cnt == 1'b1)
        move_flag <= 1'b1;
    else
        move_flag <= 1'b0;
end

// step
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        step <= 1'b0;
    else if (move_flag)
        step <= step + 1'b1;
end


always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        step_x <= 1'b0;
    else if (move_flag)begin
        if(step_x == I_cfg_win_col_num - 1'b1)
            step_x <= 'd0;
        else 
            step_x <= step_x + 1'b1;
    end
end

always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        step_y <= 1'b0;
    else if (move_flag && step_x == I_cfg_win_col_num - 1'b1 )begin
        if( step_y == I_cfg_win_row_num - 1'b1)
            step_y <= 'd0;
        else 
            step_y <= step_y + 1'b1;
    end
end

assign tmp0 = x[2:0] + y[2:0];
assign tmp1 = ~(x[2:0] - y[2:0]);


endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker:
